/*
 * Sprite.hpp
 *
 *  Created on: 15/11/2011
 *      Author: Tales
 */

#ifndef YEP_VIDEO_SPRITE_HPP
#define YEP_VIDEO_SPRITE_HPP

#include "../common.hpp"
#include "Image.hpp"
#include "../math/Vector2.hpp"
#include "../math/Rect.hpp"

namespace yep
{
/**
 * @brief Representa a animated image
 *
 * The animation is automaticly actualized each frame
 *  according the velocity. It can be copied and assigned freely because it uses
 *  the SDL_Surface's reference counting.
 *
 * The Sprite class depends on the Engine status to work, so you can not instanciate
 *  a sprite if there is not an instance of Engine.
 **/
class Sprite: public Image
{
public:
	/**
	 * @brief Creates a new sprite
	 *
	 * The given imageFile is divided in lines and collumns. The number of collumns is the
	 *  integer division between the image width and the given width. The same is occurs
	 *  to the number of lines. Each cell is an subimage (i.e. a frame of the animation).
	 *  The number of subimages is the lines times the collumns numbers.
	 *
	 * @param imageFile the path to image location. It can be any of the supported formats
	 *  of SDL_Image library.
	 * @param widht The width of an subimage.
	 * @param height The height of an subimage
	 * @throw SdlException
	 **/
	Sprite(const char *imageFile, int width, int height);

	/**
	 * @brief Copy Constructor
	 *
	 *
	 **/
	Sprite(const Sprite &other);

	/**
	 * @brief Destroys the sprite
	 *
	 * And frees the surface
	 **/
	~Sprite();

	/**
	 * @brief Copies an sprite
	 *
	 *
	 **/
	Sprite &operator =(const Sprite &other);

	/**
	 * @brief Gets the velocity
	 **/
	double getVelocity() const;

	/**
	 * @brief Sets the velocity
	 **/
	void setVelocity(double vel);

	/**
	 * @brief Gets the offset
	 **/
	unsigned getLocalOffset() const;

	/**
	 * @brief sets the offset
	 **/
	void setLocalOffset(unsigned value);

	/**
	 * @brief Returns the current index of the frame
	 *
	 *
	 **/
	Sint16 getIndex(void) const;

	/**
	 * @brief Gets the current Area of  the surface.
	 *
	 *
	 **/
	inline Rect getArea(void) const
	{
		Sint16 index = this->getIndex();
		Sint16 line = index / ncols;
		Sint16 collumn = index % ncols;
		return Rect(Sint16(collumn * width), Sint16(line * height), width, height);
	}

	/**
	 * @brief Draw the sprite onto the canvas.
	 *
	 * @param canvas the destiny surface
	 * @param position Where to draw
	 **/
	void draw(Canvas &canvas, const Vector2 &position);

	/**
	 * @brief Draw the sprite onto the canvas
	 *
	 * @param canvas the destiny surface
	 * @param position Where to draw
	 * @param sectionPosition Position to cut
	 * @param sectionSize Area to cut
	 **/
	void draw(Canvas &canvas, const Vector2 &position, const Vector2 &sectionPosition, const Vector2 &sectionSize);

	/**
	 * @brief Returns the image
	 *
	 * You can't free the returned surface, otherwise it will cause a
	 *  segmentation fault.
	 *
	 * @return The current image.
	 **/
	SDL_Surface* getSurface(void);

	/**
	 * @brief Returns the width
	 *
	 *
	 **/
	Uint16 getWidth(void) const
	{
		return width;
	}

	/**
	 * @brief Returns the height
	 *
	 *
	 **/
	Uint16 getHeight(void) const
	{
		return height;
	}

	/**
	 * @brief Returns if the pixel is transparent
	 *
	 *
	 **/
	bool transparent(unsigned line, unsigned col) const;

	/**
	 * @brief Actualizes all sprites to next frame
	 **/
	inline static void nextFrame()
	{
		++_worldFrame;
	}

private:
	unsigned _offset;
	double velocity;
	SDL_Surface *surface;
	unsigned nframes, ncols;
	Uint16 width, height;
	static Uint32 _worldFrame;

	void rawCopy(const Sprite &other);
};
}

#endif // YEP_VIDEO_SPRITE_HPP
